Skip to content

Arm backend: Add Clang bare-metal toolchain - #24831

Open
perheld wants to merge 1 commit into
pytorch:mainfrom
perheld:change-1361009
Open

perheld wants to merge 1 commit into
pytorch:mainfrom
perheld:change-1361009

Conversation

@perheld

@perheld perheld commented Nov 10, 2026 •

Copy link
Copy Markdown
Collaborator

Add Arm Toolchain for Embedded as an alternative to GCC for Arm bare-metal builds. Wire the Clang toolchain through setup, runner, and Cortex-M workflows. Add Picolibc startup, TLS, UART, scatter-loading, and linker-script integration for Corstone-300 and Corstone-320.

Test plan: Built and ran embedded-PTE runners on Corstone-300 U55 and Corstone-320 U85 FVPs with Clang 23.1.0. Verified one NPU inference and delegation with clean completion. Built the Corstone-300 U55 runner with GCC for compatibility. Verified Picolibc startup with cppcheck and compiled it with Arm Clang 23.1.0 and Arm GCC 15.2. Passed targeted lintrunner, CMake formatting, and git diff checks.

Authored with assistance from OpenAI Codex.

Change-Id: Iad2da4308cd63406bf0f015fbc5e16bfd49990d9

cc @digantdesai @freddan80 @per @zingo @oscarandersson8218 @mansnils @Sebastian-Larsson @robell @rascani

@perheld perheld added the partner: arm For backend delegation, kernels, demo, etc. from the 3rd-party partner, Arm label Nov 10, 2026
@perheld
perheld requested a review from rascani as a code owner November 10, 2026 08:18
@perheld perheld added the release notes: arm Changes to the ARM backend delegate label Nov 10, 2026
@pytorch-bot

pytorch-bot Bot commented Nov 10, 2026 •

Copy link
Copy Markdown

🔗 Helpful Links

🧪 See artifacts and rendered test results at hud.pytorch.org/pr/pytorch/executorch/24831

Note: Links to docs will display an error until the docs builds have been completed.

⏳ No Failures, 310 Pending

As of commit 8dcd4ff with merge base 6150ca0 (image):
💚 Looks good so far! There are no failures yet. 💚

This comment was automatically generated by Dr. CI and updates every 15 minutes.

@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Nov 10, 2026
@github-actions github-actions Bot added the module: arm Issues related to arm backend label Nov 10, 2026
Comment thread CMakeLists.txt Resolved
@perheld

perheld commented Nov 10, 2026

Copy link
Copy Markdown
Collaborator Author

pull / test-binary-size-linux / linux-job (pull_request) failed with gcc which is interesting, possibly due to the shuffling of things in linkerscripts?

@perheld

perheld commented Nov 10, 2026

Copy link
Copy Markdown
Collaborator Author

Will push another patch, this did indeed break the size test.

@digantdesai

Copy link
Copy Markdown
Contributor

@claude review this PR.

@claude

claude Bot commented Nov 10, 2026 •

Copy link
Copy Markdown

Claude finished @digantdesai's task in 4m 41s —— View job


PR Review: #24831

The main blocker: the new -Oz override in the root CMakeLists.txt applies to every Clang build, not just ATfE. It is almost certainly what failed test-binary-size-linux, which is a host clang12 job and never uses the Arm linker scripts. There is also a likely TLS overlap in both Corstone linker scripts.

Detailed review

Summary

This PR adds Arm Toolchain for Embedded (Clang + Picolibc) as an alternative bare-metal toolchain for Corstone-300/320 runners. There is one blocker (the -Oz scope) and one major linker-script issue (.tbss reserves no space). Several of the linker-script changes also alter GCC builds without being guarded.

Code Quality

  • .tbss is missing a space reservation, so TLS overlaps the next section.
    • Where: backends/arm/cmake/linker_scripts/Corstone-300.ld:250-256 and Corstone-320.ld:173-180.
    • Cause: .tbss is a TLS NOBITS section. Neither ld.lld nor GNU ld moves the location counter past it, so the next section in the same region starts at ADDR(.tbss). On C300 that section is .sram.rodata/.ddr.rodata. On C320 it is .ARM.extab/.ARM.exidx/the copy and zero tables in BRAM.
    • Effect: the new zero-table entry LONG(ADDR(.tbss)) LONG(SIZEOF(.tbss)/4) (C300:183, C320:212) wipes the start of that section. Every later write to TLS, such as picolibc's TLS errno, corrupts it too. On C320 this can hit the zero table while it is still being walked. The FVP runs may pass only because .tbss was empty or the clobbered bytes were never read.
    • Fix: picolibc's own picolibc.ld handles this with .tbss_space (NOLOAD) : { . = ADDR(.tbss); . = . + SIZEOF(.tbss); } right after .tbss.
    • To confirm: check llvm-readelf -S on a Clang ELF with a non-empty .tbss. (Raised by all three reviewers; inferred from the linker semantics, not linked here.)
  • Linker-script changes outside #ifdef __clang__ also change GCC images.
    • Corstone-300:
      • .got moved from .ddr into .text/ITCM (Corstone-300.ld:123-124).
      • The copy-table rodata source changed to LOADADDR(.rodata).
      • A new ALIGN(4) before __sram_data_end__.
    • Corstone-320:
      • A new rom_sram PT_LOAD (Corstone-320.ld:53).
      • .sram moved from :rom_dram to :rom_sram (:258).
    • Most of these look like fixes or no-ops, but only C300 U55 was tested with GCC. Please run C320/U85 with GCC as well, or say in the commit message that these GCC changes are intended.
  • std::random_device shim (arm-none-eabi-clang-random-device.h, force-included at arm-none-eabi-clang.cmake:49).
    • Problem: when libc++ has no random_device, the shim defines a class inside namespace std, which is undefined behaviour. It is force-included into every C++ file of every target that uses the toolchain.
    • Effect: it always returns 0x9e3779b9. Without any warning, op_rand, op_randn and op_native_dropout in kernels/portable/cpu/ produce identical output on every run, and extension/tensor/tensor_ptr_maker.cpp is affected the same way.
    • Suggestion: handle the missing random_device at those call sites (or behind an ExecuTorch macro) instead of patching std globally.
  • ArmRunnerUtilsInternal.cmake:338-348 link-option rewrite.
    • If INTERFACE_LINK_OPTIONS is unset, get_target_property returns _ethosu_target_link_options-NOTFOUND, and that string gets added as a link option. A guard is needed.
    • REMOVE_ITEM --entry Reset_Handler only works if core_platform stores those as two separate list items.
    • This check uses STREQUAL "Clang" while the root CMakeLists uses MATCHES "Clang".
    • (Low confidence: core_platform isn't in the checkout, so I couldn't check how it stores these.)
  • Tool checks resolve whatever is first on PATH, not the ATfE install.
    • examples/arm/run.sh:202 checks toolchain_compiler="clang" with command -v/hash. Because setup_path_toolchain appends ATfE to the end of PATH, a host /usr/bin/clang passes the check even when ATfE isn't installed. The build then fails later in the toolchain file.
    • build_executor_runner.sh:104 sets size_tool=llvm-size and has the same problem: it picks up the host tool if there is one. If there isn't, the size lines come out empty without an error.
    • Suggestion: use ${ATFE_TOOLCHAIN_ROOT}/bin/....

Infrastructure

  • CMakeLists.txt:316-322: the -Oz workaround applies to every Clang compiler. Blocker.
    • Problem: CMAKE_CXX_COMPILER_ID MATCHES "Clang" also matches host clang, AppleClang, the Android NDK and iOS. Every EXECUTORCH_OPTIMIZE_SIZE=ON build on those compilers switches from -Os to -Oz. That is a performance change for users who aren't on Arm.
    • CI impact: the failing job, test-binary-size-linux, runs on the clang12 image (.github/workflows/pull.yml:686); the GCC variant is a separate job. It builds a host size_test with -DEXECUTORCH_OPTIMIZE_SIZE=ON and never touches the Arm linker scripts. Its log shows Fail 48312 > 45000, against a previous size of about 44160. This flag is the only change in the diff that reaches that build, so the linker-script reshuffle is not the cause.
    • Fix: move the -Oz override into examples/arm/ethos-u-setup/arm-none-eabi-clang.cmake, or guard it on the bare-metal target, e.g. CMAKE_SYSTEM_NAME STREQUAL "Generic".
  • No CI coverage for the Clang path. The description says Clang is wired through the Cortex-M workflows, but no .ci/ or .github/ changes exercise --toolchain=arm-none-eabi-clang. The new download URL and SHA-256 values in toolchain_utils.sh are therefore unverified by CI. Consider adding at least one Corstone FVP job that uses Clang.

Recommendation

Request Changes. Limit the -Oz workaround to the Arm Clang toolchain; this should also fix the size-test failure. Add the .tbss space reservation. The remaining items are minor.

Add Arm Toolchain for Embedded as an alternative to GCC for Arm
bare-metal builds. Wire the Clang toolchain through setup, runner, and
Cortex-M workflows. Add Picolibc startup, TLS, UART, scatter-loading,
and linker-script integration for Corstone-300 and Corstone-320.

Test plan: Built and ran embedded-PTE runners on Corstone-300 U55
and Corstone-320 U85 FVPs with Clang 23.1.0. Verified one NPU
inference and delegation with clean completion. Built the Corstone-300
U55 runner with GCC for compatibility. Verified Picolibc startup with
cppcheck and compiled it with Arm Clang 23.1.0 and Arm GCC 15.2.
Passed targeted lintrunner, CMake formatting, and git diff checks.

Authored with assistance from OpenAI Codex.

Change-Id: Iad2da4308cd63406bf0f015fbc5e16bfd49990d9
Signed-off-by: Per Held <per.held@arm.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ciflow/trunk CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. module: arm Issues related to arm backend partner: arm For backend delegation, kernels, demo, etc. from the 3rd-party partner, Arm release notes: arm Changes to the ARM backend delegate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants